package com.huslee.shark.log.log4j2.core;

import com.huslee.shark.log.log4j2.interfaces.*;
import com.huslee.shark.log.log4j2.mode.MqMessage;
import com.huslee.shark.log.log4j2.mode.PVLogMessage;
import com.huslee.shark.log.log4j2.serialize.JackSon;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.message.ObjectMessage;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: zhanglin574@xdf.cn
 * @date: 2021/8/9
 * @description:
 */
public class SimpleLogger implements Logger {
    private org.apache.logging.log4j.Logger log;
    private static final org.apache.logging.log4j.Logger pvLog = LogManager.getLogger(PVLogger.class);
    private static final org.apache.logging.log4j.Logger sealInfoLog = LogManager.getLogger(SealInfoLogger.class);
    private static final org.apache.logging.log4j.Logger sealMessageLog = LogManager.getLogger(SealMessageLogger.class);
    private static final org.apache.logging.log4j.Logger mqLogger = LogManager.getLogger(MqLogger.class);
    public SimpleLogger(org.apache.logging.log4j.Logger log){
        this.log = log;
    }
    @Override
    public void info(String message) {
        this.log.info(message);
    }

    @Override
    public void info(String message, Object... args) {
        this.log.info(message, args);
    }

    @Override
    public void debug(Object obj) {
        this.log.debug(obj);

    }
    @Override
    public void debug(String message, Object obj) {
        this.log.debug(message, obj);
    }

    @Override
    public void debugJson(Object obj) {
        if(log.isDebugEnabled()){
            if (obj instanceof String){
                this.log.debug(obj);
            }else{
                this.log.debug(JackSon.toJSONString(obj));
            }
        }
    }

    @Override
    public void warn(String message) {
        this.log.warn(message);
    }

    @Override
    public void warn(String message, Object... args) {
        this.log.warn(message, args);
    }

    @Override
    public void warn(String message, Throwable t) {
        this.log.warn(message,t);
    }

    @Override
    public void error(String message) {
        this.log.error(message);
    }

    @Override
    public void error(String message, Object... args) {
        this.log.error(message, args);
    }

    @Override
    public void error(String message, Throwable e) {
        this.log.error(message,e);
    }

    @Override
    public void pv(PVLogMessage o) {
        pv(o.getProject(),o.getUrl(),o.getMethod(),o.getParams(),o.getUserId(),o.getCustom(), o.getRequestId());
    }

    @Override
    public void pv(String project, String url, String method, String params, String uid, Object custom) {
        pv(project, url, method, params, uid, custom, null);
    }

    @Override
    public void pv(String project, String url, String method, String params, String uid, Object custom, String requestId) {
        try {
            Map<String, Object> map = new HashMap();
            map.put("type", "pv_access");
            map.put("uri", url);
            map.put("method", method);
            map.put("parameters", params);
            map.put("uid", uid);
            map.put("custom", custom);
            map.put("project", project);
            map.put("request_id", requestId);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            map.put("time", sdf.format(new Date()));
            ObjectMessage objectMessage = new ObjectMessage(map);
            pvLog.info(objectMessage);
        } catch (Exception e){
            pvLog.error("",e);
        }
    }

    @Override
    public void sealInfo(String appendLogPattern, Object... appendLogArguments) {
        sealInfoWithRequestId(null, appendLogPattern, appendLogArguments);
    }

    @Override
    public void sealInfoWithRequestId(String requestId, String appendLogPattern, Object... appendLogArguments) {
        FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments);
        String appendLog = ft.getMessage();
        StackTraceElement callInfo = (new Throwable()).getStackTrace()[1];
        logSealInfo(requestId, callInfo, appendLog);
    }

    @Override
    public void message(Map<String, Object> msg, String appendLogPattern, Object... appendLogArguments) {
        FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments);
        String appendLog = ft.getMessage();
        StackTraceElement callInfo = (new Throwable()).getStackTrace()[1];
        logSealMessage(msg, callInfo, appendLog);
    }

    @Override
    public void mq(MqMessage mqMessage) {
        mq(mqMessage,null);
    }

    @Override
    public void mq(MqMessage mqMessage, Map<String, Object> extra) {
        Field[] fields = mqMessage.getClass().getDeclaredFields();
        Map<String, Object> messageMap = new HashMap<>();
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                messageMap.put(field.getName(),field.get(mqMessage));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        if(null != extra){
            messageMap.putAll(extra);
        }
        ObjectMessage objectMessage = new ObjectMessage(messageMap);
        mqLogger.info(objectMessage);
    }

    private void logSealMessage(Map<String,Object> msg, StackTraceElement callInfo, String appendLog) {
        try {
            Map<String, Object> commonMsg = getCommonMsg(null, callInfo, appendLog,"seal_message");
            if (null != msg) {
                commonMsg.putAll(msg);
            }
            ObjectMessage objectMessage = new ObjectMessage(commonMsg);
            sealMessageLog.info(objectMessage);
        } catch (Exception e) {
            sealMessageLog.error("", e);
        }
    }

    private void logSealInfo(String requestId, StackTraceElement callInfo, String appendLog) {
        try {
            Map<String, Object> commonMsg = getCommonMsg(requestId, callInfo, appendLog,"seal_info");
            ObjectMessage objectMessage = new ObjectMessage(commonMsg);
            sealInfoLog.info(objectMessage);
        } catch (Exception e) {
            sealInfoLog.error("", e);
        }
    }

    private Map<String,Object> getCommonMsg(String requestId, StackTraceElement callInfo,String appendLog,String type){
        DateTimeFormatter LOG_DTF = DateTimeFormatter
                .ofPattern("yyyy-MM-dd HH:mm:ss");
        Map<String, Object> commonMap = new HashMap();
        commonMap.put("type", type);
        commonMap.put("time", LocalDateTime.now().format(LOG_DTF));
        commonMap.put("className", callInfo.getClassName());
        commonMap.put("methodName", callInfo.getMethodName());
        commonMap.put("appendLog", appendLog);
        if (null != requestId){
            commonMap.put("requestId", requestId);
        }
        return commonMap;
    }
}
